##last modified date: 2015.3.28

import collectd
import random
import time
import subprocess
import sys
import informixdb

interval = 60
plugin_name = 'informix_mon_collectd'
sqls=[
"SELECT 'total_databases' as metric_name ,count(*) AS value from sysmaster:sysdbstab UNION SELECT 'total_tenant_databases' as metric_name , count(decode(tenant_partnum,0,NULL,1)) AS value FROM sysmaster:sysdbstab","SELECT 'total_connections' as metric_name ,ng_num_netscbs AS value from sysmaster:sysnetglobal","select 'total_spaces' as metric_name, count(*) as value from sysmaster:sysdbstab UNION select 'total_sbspaces' as metric_name, sum( decode(bitand(flags,'0x8000'),0,0,1)) as value from sysmaster:sysdbstab UNION select 'total_temp' as metric_name, sum( decode(bitand(flags,'0x2000'),0,0,1)) as value from sysmaster:sysdbstab UNION select 'total_chunks' as metric_name, sum( nchunks ) as value from sysmaster:sysdbstab","SELECT 'total_logfiles' as metric_name ,count(*) AS value from sysmaster:syslogfil UNION SELECT 'total_backup_logfiles' as metric_name , sum(decode(bitand(flags,'0x4'),0,0,1)) AS value FROM sysmaster:syslogfil","SELECT TRIM(classname)||'_num_vps' AS metric_name, COUNT(*) AS value FROM sysmaster:sysvplst GROUP BY 1 UNION SELECT TRIM(classname)||'_usecs_user' AS metric_name, TRUNC(SUM(usecs_user),2) AS value FROM sysmaster:sysvplst GROUP BY 1 UNION SELECT TRIM(classname)||'_usecs_sys' AS metric_name, TRUNC(SUM(usecs_sys),2) AS value FROM sysmaster:sysvplst GROUP BY 1 UNION SELECT TRIM(classname)||'_num_ready' AS metric_name, SUM(num_ready) AS value FROM sysmaster:sysvplst GROUP BY 1;"]

##read informix dbspace size
def read_dbspace():
	try:
		#read stdout from pipe
		p = subprocess.Popen('onstat -d',stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
		stdout = ''
		while True:
			line = p.stdout.readline()
			if line == '':
				break
			stdout+=line
		#test 
		#file=open('/opt/collectd/dbspacefile','w');
		#file.write(lines)
		#file.close()		
		lines = stdout.split('\n')
		# dbspace_dict
		# Dbspaces
		# address          number   flags      fchunk   nchunks  pgsize   flags    owner    name
		# 100cd6028        1        0x40001    1        1        4096     N  BA    informix rootdbs
		dbspace_dict = {}

		# trunk_dict
		# Chunks
		# address          chunk/dbs     offset     size       free       bpages     flags pathname
		# 100cd6268        1      1      0          125000     120371                PO-BE- /opt/informix/storage/rootdbs
		trunk_dict = {}
		for l in lines:
			tmp = l.split()
			if len(tmp) == 10:
				dbspace_dict[tmp[1]] = tmp
			if len(tmp) == 8:
				trunk_dict[tmp[1]] = tmp
		# record dbspace list
		dbspace_list = []
		for s in dbspace_dict.keys():
			# dbspace name
			name = dbspace_dict[s][9]
			id = dbspace_dict[s][1]
			if name.startswith("ds"):
				# record chunks with the specific dbs id 
				trunk_arr = []
				for t in trunk_dict.keys():
					if trunk_dict[t][2] == id:
						trunk_arr.append(t)
				if len(trunk_arr)==0:
					continue
				# total free, size
				total_free = 0
				total_size = 0
				for trunk_id in trunk_arr:
					total_free = total_free + int(trunk_dict[trunk_id][5])
					total_size = total_size + int(trunk_dict[trunk_id][4])
				ratio = total_free/(1.0*total_size)
				info = {}
				info["name"]=name
				info["free"]=total_free
				info["total"]=total_size
				info["ratio"]=ratio
				dbspace_list.append(info)
		# insert into collectd
		for dbs in dbspace_list:		
			dbspace_free = collectd.Values(type="monitor_dbspace_free",type_instance=dbs["name"], plugin=plugin_name, values=[dbs["free"]])
			dbspace_use = collectd.Values(type="monitor_dbspace_use",type_instance=dbs["name"], plugin=plugin_name, values=[dbs["total"]-dbs["free"]])
			dbspace_total = collectd.Values(type="monitor_dbspace_total",type_instance=dbs["name"], plugin=plugin_name, values=[dbs["total"]])
			dbspace_ratio = collectd.Values(type="monitor_dbspace_ratio",type_instance=dbs["name"], plugin=plugin_name, values=[dbs["ratio"]])
			dbspace_free.dispatch()
			dbspace_use.dispatch()
			dbspace_total.dispatch()
			dbspace_ratio.dispatch()
	except Exception as e:
		print e
	
##read cpu parameter
def read_cpu():
	try:
		#read stdout from pipe
		p = subprocess.Popen('vmstat',stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
		stdout = ''
		while True:
			line = p.stdout.readline()
			if line == '':
				break
			stdout+=line

		#parse stdout
		lines = stdout.split('\n')
		metric_arr = lines[1].split()
		value_arr = lines[2].split()
		para_dict = {}
		for i in range(0,len(metric_arr)):
			para_dict[metric_arr[i]] = int(value_arr[i])
			
		#insert into collectd
		cpu_user = collectd.Values(type='monitor_cpu_user',plugin=plugin_name,values=[para_dict['us']])
		cpu_system = collectd.Values(type='monitor_cpu_system',plugin=plugin_name,values=[para_dict['sy']])
		cpu_idle = collectd.Values(type='monitor_cpu_idle',plugin=plugin_name,values=[para_dict['id']])
		cpu_ratio = collectd.Values(type='monitor_cpu_ratio',plugin=plugin_name,values=[(100-para_dict['id'])*1.0/100])
		cpu_user.dispatch()
		cpu_system.dispatch()
		cpu_idle.dispatch()
		cpu_ratio.dispatch()
	except Exception as e:
		print e
		
##read memory parametor
def read_memory():
	try:
		#read stdout from pipe
		p = subprocess.Popen('vmstat',stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
		stdout = ''
		while True:
			line = p.stdout.readline()
			if line == '':
				break
			stdout+=line

		#parse stdout
		lines = stdout.split('\n')
		metric_arr = lines[1].split()
		value_arr = lines[2].split()
		para_dict = {}
		for i in range(0,len(metric_arr)):
			para_dict[metric_arr[i]] = int(value_arr[i])
			
		#insert into collectd

		cpu_swpd = collectd.Values(type='monitor_memory_swpd',plugin=plugin_name,values=[para_dict['swpd']],interval=interval)
		cpu_free = collectd.Values(type='monitor_memory_free',plugin=plugin_name,values=[para_dict['free']],interval=interval)
		cpu_buff = collectd.Values(type='monitor_memory_buff',plugin=plugin_name,values=[para_dict['buff']],interval=interval)
		cpu_cache = collectd.Values(type='monitor_memory_cache',plugin=plugin_name,values=[para_dict['cache']],interval=interval)
		total = para_dict['swpd']+para_dict['free']+para_dict['buff']+para_dict['cache']
		ratio = (total-para_dict['free'])*1.0/total
		cpu_ratio = collectd.Values(type='monitor_memory_ratio',plugin=plugin_name,values=[ratio],interval=interval)
		cpu_swpd.dispatch()
		cpu_free.dispatch()
		cpu_buff.dispatch()
		cpu_cache.dispatch()
		cpu_ratio.dispatch()
	except Exception as e:
		print e

##read disk parameter
def read_disk():
	try:
		#read stdout from pip
		p = subprocess.Popen('df',stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
		stdout = ''
		while True:
			line = p.stdout.readline()
			if line == '':
				break
			stdout+=line
		
		#parse stdout
		disks_array = stdout.split('\n')
		for i in range(1, len(disks_array)-1):
			arr = disks_array[i].split()
			filesystem = arr[0]
			total = int(arr[1])
			used = int(arr[2])
			available = int(arr[3])
			ratio = int(arr[4].split("%")[0])*1.0/100
			
			#mount == /
			if len(arr)==4:
				mount='/'
			else:
				mount = arr[5]
			
			#insert into collectd	
			disk_total = collectd.Values(type='monitor_disk_total',type_instance=mount,plugin=plugin_name,values=[total],interval=interval)
			disk_used = collectd.Values(type='monitor_disk_used',type_instance=mount,plugin=plugin_name,values=[used],interval=interval)
			disk_available = collectd.Values(type='monitor_disk_available',type_instance=mount,plugin=plugin_name,values=[available],interval=interval)
			disk_ratio = collectd.Values(type='monitor_disk_ratio',type_instance=mount,plugin=plugin_name,values=[ratio],interval=interval)
			
			#remove 0.0 ratio disk
			if ratio<=0.01:
				continue
			
			disk_total.dispatch()
			disk_used.dispatch()
			disk_available.dispatch()
			disk_ratio.dispatch()
	except Exception as e:
		print e

##read informix parameters
def read_informix():
	conn=None
	cur=None
	try:
		conn = informixdb.connect('sysuser')
		cur = conn.cursor()
		paras = {}
		for s in sqls:
			cur.execute(s)
			result = cur.fetchall()
			for j in result:
				paras[j[0]]=j[1]
		#candicate para
		candicate = ['total_tenant_databases','total_connections','total_spaces','total_logfiles','shm_num_segments']
		for k in paras:
			if not k in candicate:
				continue
			informix_para = collectd.Values()
			informix_para.type = 'monitor_informix'
			informix_para.plugin = plugin_name
			informix_para.type_instance = k
			informix_para.values = [paras[k]]
			informix_para.interval = interval
			informix_para.dispatch()	
		#vps
		vps_total = 0
		for k in paras:
			if 'vps' in k:
				vps_total = vps_total + paras[k]
		vps = collectd.Values()
		vps.type = 'monitor_informix'
		vps.plugin = plugin_name
		vps.type_instance = 'vps_total'
		vps.values = [vps_total]
		vps.interval = interval
		vps.dispatch()	
	except Exception as e:
		print e
	finally:
		if cur:
			cur.close()
		if conn:
			conn.close()
			
def config(c):
	global interval
		
	if c is None:
		pass
    
	for child in c.children:
		if child.key == 'INTERVAL':
			interval = child.values[0]
	pass
	
def init():
	global conn
	try:
		conn = informixdb.connect('sysuser')
	except Exception as e:
		print e

			
def read(data=None):
	read_memory()
	read_cpu()
	read_dbspace()
	read_disk()
	read_informix()

def write(v, data=None):
	print v
		

def shutdown():
	pass
collectd.register_init(init)
collectd.register_config(config)
collectd.register_read(read)
collectd.register_write(write)
collectd.register_shutdown(shutdown)